package com.yykj.hospital.server.service.banci.impl;

import com.yykj.common.constant.CommonConstant;
import com.yykj.common.enums.HospitalOnlineTypeEnum;
import com.yykj.common.enums.ResultEnums;
import com.yykj.common.exception.NormalException;
import com.yykj.hospital.client.dto.DoctorAvailableOnlineDTO;
import com.yykj.hospital.client.dto.banci.DoctorAvailableAppointmentDTO;
import com.yykj.hospital.server.form.BanCiSearchForm;
import com.yykj.hospital.server.model.entity.HospitalDoctor;
import com.yykj.hospital.server.model.entity.banci.HospitalDoctorBanCi;
import com.yykj.hospital.server.model.repository.banci.HospitalDoctorBanCiRepository;
import com.yykj.hospital.server.service.banci.BanCiSearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;

@Service
public class BanCiSearchServiceImpl implements BanCiSearchService {

    @Override
    public List<HospitalDoctorBanCi> searchBanCi(BanCiSearchForm form) {


        List<HospitalDoctorBanCi> doctorBanCiList = banCiRepository.findAll(new Specification<HospitalDoctorBanCi>() {
            @Override
            public Predicate toPredicate(Root<HospitalDoctorBanCi> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                List<Predicate> predicateList = new ArrayList<>();
                if (form.getHospitalId() != null && form.getHospitalId() > 0) {
                    predicateList.add(builder.equal(root.get("hospitalId"), form.getHospitalId()));
                }
                if (form.getDepId() != null && form.getDepId() > 0) {
                    predicateList.add(builder.equal(root.get("depId"), form.getDepId()));
                }

                if (!StringUtils.isEmpty(form.getDoctorId())) {
                    predicateList.add(builder.equal(root.get("doctorId"), form.getDoctorId()));
                }

                if (form.getBaseTime() != null) {
                    LocalDate nowDate = form.getBaseTime().toLocalDate();
                    LocalTime nowTime = form.getBaseTime().toLocalTime().plusMinutes(CommonConstant.BEFORE_APPOINTMENT_MINUTE);

                    Predicate p1 = builder.equal(root.get("day"), nowDate);
                    Predicate p2 = builder.greaterThanOrEqualTo(root.get("startTime"), nowTime);
                    Predicate p3 = builder.greaterThan(root.get("day"), nowDate);
                    Predicate p4 = builder.and(p1, p2);
                    predicateList.add(builder.or(p3, p4));
                }

                if (form.getType() != null) {
                    predicateList.add(builder.equal(root.get("banCiType"), form.getType()));
                }

                if (form.getDay() != null) {
                    predicateList.add(builder.equal(root.get("day"), form.getDay()));
                }

                if (form.getLevelId() != null) {
                    predicateList.add(builder.equal(root.get("levelId"), form.getLevelId()));
                }


                Predicate[] predicates = new Predicate[predicateList.size()];
                return query.where(predicateList.toArray(predicates)).getRestriction();
            }
        }, Sort.by(Sort.Order.asc("day"), Sort.Order.asc("startTime")));
        return doctorBanCiList;
    }

    @Override
    public DoctorAvailableAppointmentDTO checkAvailableAppointmentCnt(String doctorId, Integer appointId) {
        HospitalDoctorBanCi doctorBanCi = banCiRepository.findById(appointId).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        if (!doctorBanCi.getDoctorId().equals(doctorId)) {
            throw new NormalException(ResultEnums.NOT_EXIST);
        }
        DoctorAvailableAppointmentDTO dto = new DoctorAvailableAppointmentDTO();
        dto.setAppointId(appointId);
        dto.setDoctorId(doctorId);
        dto.setRemain(doctorBanCi.getAppointment() - doctorBanCi.getAppointmentUsed());
        dto.setTotalCnt(doctorBanCi.getAppointment());
        return dto;
    }

    @Override
    public DoctorAvailableOnlineDTO checkAvailableOnlineCnt(String doctorId, Integer appointId, HospitalOnlineTypeEnum type) {
        HospitalDoctorBanCi doctorBanCi = banCiRepository.findById(appointId).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        if (!doctorBanCi.getDoctorId().equals(doctorId)) {
            throw new NormalException(ResultEnums.NOT_EXIST);
        }
        DoctorAvailableOnlineDTO dto = new DoctorAvailableOnlineDTO();
        dto.setAppointId(appointId);
        dto.setDoctorId(doctorId);
        dto.setType(type);
        switch (type) {
            case video:
                dto.setRemain(doctorBanCi.getVideo() - doctorBanCi.getVideoUsed());
                dto.setTotalCnt(doctorBanCi.getVideo());
                break;
            case voice:
                dto.setRemain(doctorBanCi.getVoice() - doctorBanCi.getVoiceUsed());
                dto.setTotalCnt(doctorBanCi.getVoice());
                break;
            case pic:
                dto.setRemain(doctorBanCi.getPic() - doctorBanCi.getPicUsed());
                dto.setTotalCnt(doctorBanCi.getPic());
                break;
            default:
                break;
        }
        return dto;
    }

    private HospitalDoctorBanCiRepository banCiRepository;

    @Autowired
    public void setBanCiRepository(HospitalDoctorBanCiRepository banCiRepository) {
        this.banCiRepository = banCiRepository;
    }
}
